package org.wheel.plugins.toolkit.jdbc.pool.util.excution;


import cn.hutool.core.util.ArrayUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.wheel.module.core.util.Page;
import org.wheel.plugins.toolkit.jdbc.pool.bean.DatabaseConnection;
import org.wheel.plugins.toolkit.jsqlparse.helper.ParamValueConvert;
import org.wheel.plugins.toolkit.sql.core.GlobalConfig;
import org.wheel.plugins.toolkit.sql.enums.SqlModel;
import org.wheel.plugins.toolkit.util.sql.SQLHelper;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 分页专属 Executor
 */
public class SqlPageExecutor {

    private final SqlQueryExecutor queryExecutor = new SqlQueryExecutor();

    // 直接使用 LogFactory 创建日志对象，Hutool 会自动检测项目中的日志框架（优先级：Slf4j > Log4j > Logback > JDK Logging）
    private static final Log log = LogFactory.get();

    /* ================== 返回 Map ================== */

    public Page<Map<String, Object>> queryPage(DatabaseConnection conn,
                                               String pageSql,
                                               LinkedHashMap<String, Object> param,
                                               SqlModel model) {
        long[] info = SQLHelper.getPageInfo(pageSql);
        if (ArrayUtil.isEmpty(info)) {
            throw new IllegalArgumentException("分页 SQL 格式不正确，缺少 #page{}/{}# 片段");
        }
        long pageSize = info[0];
        long pageNo   = info[1];
        return queryPage(conn, pageSql, param, pageNo, pageSize, model);
    }

    public Page<Map<String, Object>> queryPage(DatabaseConnection conn,
                                               String pageSql,
                                               LinkedHashMap<String, Object> param,
                                               long pageNo,
                                               long pageSize,
                                               SqlModel model) {
        String countSql = SQLHelper.countSqlHandler(pageSql);
        long total = count(conn, countSql, param, model);
        log.debug("total: {}", total);
        Page<Map<String, Object>> page = new Page<>((int) pageNo, (int) pageSize, total);
        if (total > 0 && pageSize > 0) {
            String finalPageSql = rebuildPageSql(pageSql, pageNo, pageSize);
            log.trace("exec SQL: {}", ParamValueConvert.convertValuesIntoSql(finalPageSql, param, GlobalConfig.getDialect()));
            List<Map<String, Object>> list = queryExecutor.queryForList(conn, finalPageSql, param, model);
            page.setList(list);
        }
        return page;
    }

    /**
     * 不做任何校验，直接查询分页数据
     * @param conn 数据库连接
     * @param querySql 查询 SQL
     * @param pageNo 页码
     * @param pageSize 页大小
     * @param param 参数
     * @param model 模型
     * @return  List分页集合数据
     */
    public List<Map<String, Object>> queryList(DatabaseConnection conn,
                                               String querySql,
                                               long pageNo,
                                               long pageSize,
                                               LinkedHashMap<String, Object> param,
                                               SqlModel model) {
        String finalPageSql = rebuildPageSql(querySql, pageNo, pageSize);
        return queryExecutor.queryForList(conn, finalPageSql, param, model);
    }

    /**
     * 不做任何校验，直接查询分页数据
     * @param conn 数据库连接
     * @param querySql 查询 SQL
     * @param pageNo 页码
     * @param pageSize 页大小
     * @param param 参数
     * @param model 模型
     * @param elementType 返回的元素类型
     * @return List分页集合数据
     * @param <T> 返回的元素类型
     */
    public <T> List<T> queryList(DatabaseConnection conn,
                                 String querySql,
                                 long pageNo,
                                 long pageSize,
                                 LinkedHashMap<String, Object> param,
                                 SqlModel model,
                                 Class<T> elementType) {
        String finalPageSql = rebuildPageSql(querySql, pageNo, pageSize);
        return queryExecutor.queryForList(conn, finalPageSql, param, model, elementType);
    }

    public Page<Map<String, Object>> queryPage(DatabaseConnection conn,
                                               String countSql,
                                               String pageSql,
                                               LinkedHashMap<String, Object> param,
                                               long pageNo,
                                               long pageSize,
                                               SqlModel model) {
        long total = count(conn, countSql, param, model);
        log.debug("total: {}", total);
        Page<Map<String, Object>> page = new Page<>((int) pageNo, (int) pageSize, total);
        if (total > 0 && pageSize > 0) {
            log.trace("exec SQL: {}", ParamValueConvert.convertValuesIntoSql(pageSql, param, GlobalConfig.getDialect()));
            List<Map<String, Object>> list = queryExecutor.queryForList(conn, pageSql, param, model);
            page.setList(list);
        }
        return page;
    }

    /* ================== 返回 Bean ================== */

    public <T> Page<T> queryPage(DatabaseConnection conn,
                                 String pageSql,
                                 LinkedHashMap<String, Object> param,
                                 long pageNo,
                                 long pageSize,
                                 SqlModel model,
                                 Class<T> elementType) {
        String countSql = SQLHelper.countSqlHandler(pageSql);
        long total = count(conn, countSql, param, model);
        log.debug("total: {}", total);
        Page<T> page = new Page<>((int) pageNo, (int) pageSize, total);
        if (total > 0 && pageSize > 0) {
            String finalPageSql = rebuildPageSql(pageSql, pageNo, pageSize);
            log.trace("exec SQL: {}", ParamValueConvert.convertValuesIntoSql(finalPageSql, param, GlobalConfig.getDialect()));
            List<T> list = queryExecutor.queryForList(conn, finalPageSql, param, model, elementType);
            page.setList(list);
        }
        return page;
    }

    public <T> Page<T> queryPage(DatabaseConnection conn,
                                 String countSql,
                                 String pageSql,
                                 LinkedHashMap<String, Object> param,
                                 long pageNo,
                                 long pageSize,
                                 SqlModel model,
                                 Class<T> elementType) {
        long total = count(conn, countSql, param, model);
        log.debug("total: {}", total);
        Page<T> page = new Page<>((int) pageNo, (int) pageSize, total);
        if (total > 0 && pageSize > 0) {
            List<T> list = queryExecutor.queryForList(conn, pageSql, param, model, elementType);
            page.setList(list);
        }
        return page;
    }

    /* ================== 内部工具 ================== */

    private long count(DatabaseConnection conn, String countSql, LinkedHashMap<String, Object> param, SqlModel model) {
        return queryExecutor.executeCountSqlQuery(conn, countSql, param, model);
//        return queryExecutor.queryForObject(conn, countSql, param, model, Long.class);
    }

    public String rebuildPageSql(String sql, long pageNo, long pageSize) {
        long[] ori = SQLHelper.getPageInfo(sql);
        if (ori == null || ori[0] != pageSize || ori[1] != pageNo) {
            return SQLHelper.resetSqlPageInfo(sql, pageNo, pageSize);
        }
        return sql;
    }
}